// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <cstdint>
#include <stdexcept>
#include <string>
#include <type_traits>

#include <pollux/common/strings/string_view.h>
#include <pollux/type/timestamp.h>
#include <pollux/type/type.h>

// Miscellaneous utilities regarding type, to avoid duplication
// and improve readability in places that have to reason about types.

namespace kumo::pollux {
    /**
     * @return true iff the type T can be used in a biased vector
     */
    template<typename T>
    constexpr bool admitsBias() {
        return std::is_same_v<T, int64_t> || std::is_same_v<T, int32_t> ||
               std::is_same_v<T, int16_t>;
    }

    /**
     * @return true if the type is integral but not Boolean
     */
    template<typename T>
    constexpr bool isIntegral() {
        return std::is_integral_v<T> && !std::is_same_v<T, bool>;
    }

    /**
     * @return true if the type can be used in a dictionary encoding, false
     * otherwise
     */
    template<typename T>
    constexpr bool admitsDictionary() {
        return std::is_same_v<T, int128_t> || std::is_same_v<T, int64_t> ||
               std::is_same_v<T, double> || std::is_same_v<T, StringView> ||
               std::is_same_v<T, pollux::Timestamp>;
    }

    /**
     * @return true if the type can be used as a MapVector key.
     */
    template<typename KeyType>
    constexpr bool allowsMapKey() {
        // MapVector only allows simple types with the exception of floating
        // point values.
        return std::is_same_v<KeyType, int8_t> || std::is_same_v<KeyType, uint8_t> ||
               std::is_same_v<KeyType, int16_t> || std::is_same_v<KeyType, uint16_t> ||
               std::is_same_v<KeyType, int32_t> || std::is_same_v<KeyType, uint32_t> ||
               std::is_same_v<KeyType, int64_t> || std::is_same_v<KeyType, uint64_t> ||
               std::is_same_v<KeyType, bool> || std::is_same_v<KeyType, StringView>;
    }

    /**
     * @return true if delta (absolute difference between max and min values)
     * is small enough to use bias for the given type
     */
    template<typename T>
    inline bool deltaAllowsBias(uint64_t delta) {
        return false;
    }

    template<>
    inline bool deltaAllowsBias<int64_t>(uint64_t delta) {
        return delta <= std::numeric_limits<uint32_t>::max();
    }

    template<>
    inline bool deltaAllowsBias<int32_t>(uint64_t delta) {
        return delta <= std::numeric_limits<uint16_t>::max();
    }

    template<>
    inline bool deltaAllowsBias<int16_t>(uint64_t delta) {
        return delta <= std::numeric_limits<uint8_t>::max();
    }
} // namespace kumo::pollux
